package com.it.App.filter;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.it.App.entity.LoginUser;
import com.it.App.entity.SysUser;
import com.it.App.utils.JwtUtils;
import com.it.App.utils.RedisUtil;
import com.it.App.vo.Const;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;

/**
 * @Author: CaoYouGen
 * @DateTime: 2023/11/22/15:08
 * @注释: TODO
 **/
@Component
@Slf4j
public class JWTAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private RedisUtil redisUtil;

    // 进行JWT校验的过滤操作
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 日志记录JWT校验过滤器的执行
        log.info("JWT校验过滤器执行");
        // 从请求头中获取JWT
        String token = request.getHeader("token");

        // 如果token为空，则放行，继续处理下一个过滤器
        if (StrUtil.isBlankOrUndefined(token)) {
            chain.doFilter(request, response);
            return;
        }

        // token不为空 使用Jwt工具类 解析获取声明
        Claims claims = jwtUtils.getClaimByToken(token);

        // 如果 token异常 则抛出异常
        if (claims == null) {
            throw new RuntimeException("Token异常");
        }
        // 如果 token已过期 则抛出异常
        if (jwtUtils.isTokenExpired(claims)) {
            throw new RuntimeException("Token已过期");
        }

        // 从token中获取用户id
        String userId = claims.getSubject();
        // 从redis中获取用户的全部信息
        LoginUser loginUser = (LoginUser) redisUtil.hget(Const.Login_Key, userId);
        if (ObjectUtil.isNull(loginUser)) {
            throw new RuntimeException("鉴权失败！请求重新登录。");
        }
//            LoginUser loginUser = objectMapper.readValue(loginUserStr, LoginUser.class);
        SysUser sysUser = loginUser.getSysUser();
        // 日志记录正在登录的用户信息
        log.info("用户-{}，正在登录！", sysUser.getUsername());

        // TODO 获取权限信息封装到Authentication中
        Collection<? extends GrantedAuthority> authorities = loginUser.getAuthorities();
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, authorities);
        // 将认证信息设置到安全上下文中
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        // 继续处理请求
        chain.doFilter(request, response);
    }
}
